/*
Copyright 2010 GHI Electronics LLC
Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. 
*/

using System;
using Microsoft.SPOT.Hardware;

namespace GHIElectronics.NETMF.FEZ
{
    public static partial class FEZ_Components
    {
        #region Nested type: Relay16

        public class Relay16 : IDisposable
        {
            #region RelayChannel enum

            public enum RelayChannel
            {
                Ch1,
                Ch2,
                Ch3,
                Ch4,
                Ch5,
                Ch6,
                Ch7,
                Ch8,
                Ch9,
                Ch10,
                Ch11,
                Ch12,
                Ch13,
                Ch14,
                Ch15,
                Ch16,
                Ch17,
                Ch18,
                Ch19,
                Ch20,
                Ch21,
                Ch22,
                Ch23,
                Ch24,
                Ch25,
                Ch26,
                Ch27,
                Ch28,
                Ch29,
                Ch30,
                Ch31,
                Ch32,
                Ch33,
                Ch34,
                Ch35,
                Ch36,
                Ch37,
                Ch38,
                Ch39,
                Ch40,
                Ch41,
                Ch42,
                Ch43,
                Ch44,
                Ch45,
                Ch46,
                Ch47,
                Ch48,
                Ch49,
                Ch50,
                Ch51,
                Ch52,
                Ch53,
                Ch54,
                Ch55,
                Ch56,
                Ch57,
                Ch58,
                Ch59,
                Ch60,
                Ch61,
                Ch62,
                Ch63,
                Ch64,
                Ch65,
                Ch66,
                Ch67,
                Ch68,
                Ch69,
                Ch70,
                Ch71,
                Ch72,
                Ch73,
                Ch74,
                Ch75,
                Ch76,
                Ch77,
                Ch78,
                Ch79,
                Ch80,
                Ch81,
                Ch82,
                Ch83,
                Ch84,
                Ch85,
                Ch86,
                Ch87,
                Ch88,
                Ch89,
                Ch90,
                Ch91,
                Ch92,
                Ch93,
                Ch94,
                Ch95,
                Ch96,
                Ch97,
                Ch98,
                Ch99,
                Ch100,
                Ch101,
                Ch102,
                Ch103,
                Ch104,
                Ch105,
                Ch106,
                Ch107,
                Ch108,
                Ch109,
                Ch110,
                Ch111,
                Ch112,
                Ch113,
                Ch114,
                Ch115,
                Ch116,
                Ch117,
                Ch118,
                Ch119,
                Ch120,
                Ch121,
                Ch122,
                Ch123,
                Ch124,
                Ch125,
                Ch126,
                Ch127,
                Ch128,
            }

            #endregion

            private readonly I2CDevice _i2C;
            private const int ClockRate = 80;
            private readonly ushort[] _channels=new ushort[8];
            private readonly I2CDevice.Configuration[] _relayBoardConfigs = {
                                                                                new I2CDevice.Configuration(0x20, ClockRate),
                                                                                new I2CDevice.Configuration(0x21, ClockRate),
                                                                                new I2CDevice.Configuration(0x22, ClockRate),
                                                                                new I2CDevice.Configuration(0x23, ClockRate),
                                                                                new I2CDevice.Configuration(0x24, ClockRate),
                                                                                new I2CDevice.Configuration(0x25, ClockRate),
                                                                                new I2CDevice.Configuration(0x26, ClockRate),
                                                                                new I2CDevice.Configuration(0x27, ClockRate)
                                                                            };

            //private ushort _channels;
            private I2CDevice.I2CTransaction[] _xaction;


            public Relay16()
            {
                
                MAXBoards = 8;

                _i2C = new I2CDevice(_relayBoardConfigs[0]);

                for (int c = 0; c < MAXBoards; c++)
                {
                    _channels[0] = 123;
                    _i2C.Config = _relayBoardConfigs[c];

                    //make all pins outputs
                    _xaction = new I2CDevice.I2CTransaction[1];
                    _xaction[0] = I2CDevice.CreateWriteTransaction(new byte[] {0x06, 0x00});

                    if (_i2C.Execute(_xaction, ClockRate) == 0)
                    {
                        if (c == 0)
                            new Exception("Failed to send I2C data to board " + c);
                        MAXBoards = c;
                       
                    }
                    //xaction[0] = I2C.CreateWriteTransaction(new byte[] { 0x07, 0x00 });
                    _xaction[0].Buffer[0] = 7;
                    if (_i2C.Execute(_xaction, ClockRate) == 0)
                    {
                        if (c == 0)
                            new Exception("Failed to send I2C data to board " + c);
                        MAXBoards = c;
                       
                    }

                    SetAllChannels(0, c);
                }
            }

            public static int MAXBoards { get; private set; }

            #region IDisposable Members

            public void Dispose()
            {
                _i2C.Dispose();
                _xaction = null;
            }

            #endregion

            public static RelayChannel GetRelayFromNum(int relaynum)
            {
                switch (relaynum)
                {
                    case 1:
                        return RelayChannel.Ch1;
                       
                    case 2:
                        return RelayChannel.Ch2;
                       
                    case 3:
                        return RelayChannel.Ch3;
                       
                    case 4:
                        return RelayChannel.Ch4;
                       
                    case 5:
                        return RelayChannel.Ch5;
                       
                    case 6:
                        return RelayChannel.Ch6;
                       
                    case 7:
                        return RelayChannel.Ch7;
                       
                    case 8:
                        return RelayChannel.Ch8;
                       
                    case 9:
                        return RelayChannel.Ch9;
                       
                    case 10:
                        return RelayChannel.Ch10;
                       
                    case 11:
                        return RelayChannel.Ch11;
                       
                    case 12:
                        return RelayChannel.Ch12;
                       
                    case 13:
                        return RelayChannel.Ch13;
                       
                    case 14:
                        return RelayChannel.Ch14;
                       
                    case 15:
                        return RelayChannel.Ch15;
                       
                    case 16:
                        return RelayChannel.Ch16;
                       
                    case 17:
                        return RelayChannel.Ch17;
                       
                    case 18:
                        return RelayChannel.Ch18;
                       
                    case 19:
                        return RelayChannel.Ch19;
                       
                    case 20:
                        return RelayChannel.Ch20;
                       
                    case 21:
                        return RelayChannel.Ch21;
                       
                    case 22:
                        return RelayChannel.Ch22;
                       
                    case 23:
                        return RelayChannel.Ch23;
                       
                    case 24:
                        return RelayChannel.Ch24;
                       
                    case 25:
                        return RelayChannel.Ch25;
                       
                    case 26:
                        return RelayChannel.Ch26;
                       
                    case 27:
                        return RelayChannel.Ch27;
                       
                    case 28:
                        return RelayChannel.Ch28;
                       
                    case 29:
                        return RelayChannel.Ch29;
                       
                    case 30:
                        return RelayChannel.Ch30;
                       
                    case 31:
                        return RelayChannel.Ch31;
                       
                    case 32:
                        return RelayChannel.Ch32;
                       
                    case 33:
                        return RelayChannel.Ch33;
                       
                    case 34:
                        return RelayChannel.Ch34;
                       
                    case 35:
                        return RelayChannel.Ch35;
                       
                    case 36:
                        return RelayChannel.Ch36;
                       
                    case 37:
                        return RelayChannel.Ch37;
                       
                    case 38:
                        return RelayChannel.Ch38;
                       
                    case 39:
                        return RelayChannel.Ch39;
                       
                    case 40:
                        return RelayChannel.Ch40;
                       
                    case 41:
                        return RelayChannel.Ch41;
                       
                    case 42:
                        return RelayChannel.Ch42;
                       
                    case 43:
                        return RelayChannel.Ch43;
                       
                    case 44:
                        return RelayChannel.Ch44;
                       
                    case 45:
                        return RelayChannel.Ch45;
                       
                    case 46:
                        return RelayChannel.Ch46;
                       
                    case 47:
                        return RelayChannel.Ch47;
                       
                    case 48:
                        return RelayChannel.Ch48;
                       
                    case 49:
                        return RelayChannel.Ch49;
                       
                    case 50:
                        return RelayChannel.Ch50;
                       
                    case 51:
                        return RelayChannel.Ch51;
                       
                    case 52:
                        return RelayChannel.Ch52;
                       
                    case 53:
                        return RelayChannel.Ch53;
                       
                    case 54:
                        return RelayChannel.Ch54;
                       
                    case 55:
                        return RelayChannel.Ch55;
                       
                    case 56:
                        return RelayChannel.Ch56;
                       
                    case 57:
                        return RelayChannel.Ch57;
                       
                    case 58:
                        return RelayChannel.Ch58;
                       
                    case 59:
                        return RelayChannel.Ch59;
                       
                    case 60:
                        return RelayChannel.Ch60;
                       
                    case 61:
                        return RelayChannel.Ch61;
                       
                    case 62:
                        return RelayChannel.Ch62;
                       
                    case 63:
                        return RelayChannel.Ch63;
                       
                    case 64:
                        return RelayChannel.Ch64;
                       
                    case 65:
                        return RelayChannel.Ch65;
                       
                    case 66:
                        return RelayChannel.Ch66;
                       
                    case 67:
                        return RelayChannel.Ch67;
                       
                    case 68:
                        return RelayChannel.Ch68;
                       
                    case 69:
                        return RelayChannel.Ch69;
                       
                    case 70:
                        return RelayChannel.Ch70;
                       
                    case 71:
                        return RelayChannel.Ch71;
                       
                    case 72:
                        return RelayChannel.Ch72;
                       
                    case 73:
                        return RelayChannel.Ch73;
                       
                    case 74:
                        return RelayChannel.Ch74;
                       
                    case 75:
                        return RelayChannel.Ch75;
                       
                    case 76:
                        return RelayChannel.Ch76;
                       
                    case 77:
                        return RelayChannel.Ch77;
                       
                    case 78:
                        return RelayChannel.Ch78;
                       
                    case 79:
                        return RelayChannel.Ch79;
                       
                    case 80:
                        return RelayChannel.Ch80;
                       
                    case 81:
                        return RelayChannel.Ch81;
                       
                    case 82:
                        return RelayChannel.Ch82;
                       
                    case 83:
                        return RelayChannel.Ch83;
                       
                    case 84:
                        return RelayChannel.Ch84;
                       
                    case 85:
                        return RelayChannel.Ch85;
                       
                    case 86:
                        return RelayChannel.Ch86;
                       
                    case 87:
                        return RelayChannel.Ch87;
                       
                    case 88:
                        return RelayChannel.Ch88;
                       
                    case 89:
                        return RelayChannel.Ch89;
                       
                    case 90:
                        return RelayChannel.Ch90;
                       
                    case 91:
                        return RelayChannel.Ch91;
                       
                    case 92:
                        return RelayChannel.Ch92;
                       
                    case 93:
                        return RelayChannel.Ch93;
                       
                    case 94:
                        return RelayChannel.Ch94;
                       
                    case 95:
                        return RelayChannel.Ch95;
                       
                    case 96:
                        return RelayChannel.Ch96;
                       
                    case 97:
                        return RelayChannel.Ch97;
                       
                    case 98:
                        return RelayChannel.Ch98;
                       
                    case 99:
                        return RelayChannel.Ch99;
                       
                    case 100:
                        return RelayChannel.Ch100;
                       
                    case 101:
                        return RelayChannel.Ch101;
                       
                    case 102:
                        return RelayChannel.Ch102;
                       
                    case 103:
                        return RelayChannel.Ch103;
                       
                    case 104:
                        return RelayChannel.Ch104;
                       
                    case 105:
                        return RelayChannel.Ch105;
                       
                    case 106:
                        return RelayChannel.Ch106;
                       
                    case 107:
                        return RelayChannel.Ch107;
                       
                    case 108:
                        return RelayChannel.Ch108;
                       
                    case 109:
                        return RelayChannel.Ch109;
                       
                    case 110:
                        return RelayChannel.Ch110;
                       
                    case 111:
                        return RelayChannel.Ch111;
                       
                    case 112:
                        return RelayChannel.Ch112;
                       
                    case 113:
                        return RelayChannel.Ch113;
                       
                    case 114:
                        return RelayChannel.Ch114;
                       
                    case 115:
                        return RelayChannel.Ch115;
                       
                    case 116:
                        return RelayChannel.Ch116;
                       
                    case 117:
                        return RelayChannel.Ch117;
                       
                    case 118:
                        return RelayChannel.Ch118;
                       
                    case 119:
                        return RelayChannel.Ch119;
                       
                    case 120:
                        return RelayChannel.Ch120;
                       
                    case 121:
                        return RelayChannel.Ch121;
                       
                    case 122:
                        return RelayChannel.Ch122;
                       
                    case 123:
                        return RelayChannel.Ch123;
                       
                }

                return RelayChannel.Ch1;
            }

            public void SetAllChannels(ushort channels, int boardNumber)
            {
                if (_channels[boardNumber] == channels)
                    return;
                _i2C.Config = _relayBoardConfigs[boardNumber];
                //send low order
                //xaction[0] = I2C.CreateWriteTransaction(new byte[] { 0x02, (byte)channels });
                _xaction[0].Buffer[0] = 0x02;
                _xaction[0].Buffer[1] = (byte) channels;
                if (_i2C.Execute(_xaction, ClockRate) == 0)
                {
                    new Exception("Failed to send I2C data");
                }
                //send high order
                //xaction[0] = I2C.CreateWriteTransaction(new byte[] { 0x03, (byte)(channels>>8) });
                _xaction[0].Buffer[0] = 0x03;
                _xaction[0].Buffer[1] = (byte) (channels >> 8);
                if (_i2C.Execute(_xaction, ClockRate) == 0)
                {
                    new Exception("Failed to send I2C data");
                }

                _channels[boardNumber] = channels;
            }

            public void TurnOn(RelayChannel channel)
            {
                var relay = (byte) channel;

                var boardNum = (byte)(relay / 16);

                relay = (byte)(relay % 16);

                var mask = (ushort)(1u << relay);
                SetAllChannels((ushort)(_channels[boardNum] | mask), boardNum);
            }

            public void ShutOff(RelayChannel channel)
            {
                var relay = (byte)channel;

                var boardNum = (byte)(relay / 16);

                relay = (byte)(relay % 16);

                var mask = (ushort)(~(1u << relay));
                SetAllChannels((ushort)(_channels[boardNum] & mask), boardNum);
            }

            public void ShutAllOff()
            {
                for (int c = 0; c < MAXBoards; c++)
                {
                    SetAllChannels(0, c);
                }
            }
        }

        #endregion
    }
}